/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.cratos.xxgram.platf.message;

import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.util.Arrays;
import java.util.Base64;
import java.util.List;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import org.redkale.service.RetResult;
import org.redkale.source.ColumnValue;
import org.redkale.source.DataSource;
import org.redkale.source.FilterExpress;
import org.redkale.source.FilterFunc;
import org.redkale.source.FilterNode;
import org.redkale.util.Comment;
import org.redkale.util.Utility;

import com.cratos.xxgram.platf.base.RetCodes;
import com.cratos.xxgram.platf.base.UserInfo;
import com.cratos.xxgram.platf.friend.FriendAsk;
import com.cratos.xxgram.platf.friend.FriendShip;
import com.cratos.xxgram.platf.group.GroupDetail;
import com.cratos.xxgram.platf.group.UserGroup;
import com.cratos.xxgram.platf.message.BaseContent.MentionedInfo;
import com.cratos.xxgram.platf.message.BasicContent.TextMessage;
import com.cratos.xxgram.platf.message.NotifyContent.AddMemberToGroupNotify;
import com.cratos.xxgram.platf.message.NotifyContent.ContactNotificationMessage;
import com.cratos.xxgram.platf.message.NotifyContent.CreateGroupNotify;
import com.cratos.xxgram.platf.message.NotifyContent.DissMissGroupNotify;
import com.cratos.xxgram.platf.message.NotifyContent.InformationNotificationMessage;
import com.cratos.xxgram.platf.message.NotifyContent.KickedGroupNotify;
import com.cratos.xxgram.platf.message.NotifyContent.QuitGroupNotify;
import com.cratos.xxgram.platf.message.NotifyContent.ReadReceiptMessage;
import com.cratos.xxgram.platf.message.NotifyContent.StealthWithFriendsNotify;
import com.cratos.xxgram.platf.message.NotifyContent.UpdateGroupNotify;
import com.cratos.xxgram.platf.message.NotifyContent.UpdateUserGroupNameNotify;
import com.cratos.xxgram.platf.message.NotifyContent.UserOnlineStatusNotify;
import com.cratos.xxgram.platf.message.NotifyContent.ForBiddenWordNotify;
import com.cratos.xxgram.platf.message.NotifyContent.GroupReadReceiptNotify;
import com.cratos.xxgram.platf.user.UserDetail;
import com.cratos.xxgram.platf.util.Cryptos;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import org.redkale.source.Flipper;

import static com.cratos.xxgram.platf.base.MsgConstant.*;
/**
 * @author SquRab
 */
public abstract class NotifyHandler extends MessageHandler {

    @Comment("提示小灰条通知消息")
    public static final class InformationNotificationHandler extends NotifyHandler {

        public static final MessageHandler instance = new InformationNotificationHandler();

        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {

            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            try {
                sendMessage(messageService, record);// 发送消息
                feature.complete(record);
            } catch (Exception e) {
                feature.completeExceptionally(e);
            }
            return feature;
        }

        @Override
        public Class getContentClass() {
            return InformationNotificationMessage.class;
        }
    }

    @Comment("联系人(好友)通知消息 用来发送联系人操作（加好友等）的通知消息，客户端收到消息后进行存储，不计入未读消息数，此类型消息没有 Push 通知。 RC:ContactNtf")
    public static final class ContactNotificationHanler extends NotifyHandler {

        public static final MessageHandler instance = new ContactNotificationHanler();

        /**
         * 重写校验方法
         */
        @Override
        protected RetResult validate(MessageService messageService, MessageRecord record) {
            // 基础校验
            RetResult rs = super.validate(messageService, record);
            if (!rs.isSuccess()) {
                return rs;
            }
            // 校验需要添加的用户在系统中存不存在
            UserDetail userDetail = messageService.getSource().find(UserDetail.class, record.getFromid());
            UserDetail friendDetail = messageService.getSource().find(UserDetail.class, record.getTargetid());
            if (userDetail == null || friendDetail == null) {
                return RetCodes.retResult(RetCodes.RET_USER_NOTEXISTS);
            }
            // 校验当前用户是不是已经是好友了
            boolean exist = messageService.getSource().exists(FriendShip.class,
                    FilterNode.create("userid", FilterExpress.EQUAL, record.getFromid())
                            .and("friendid", FilterExpress.EQUAL, record.getTargetid())
                            .or(FilterNode.create("userid", FilterExpress.EQUAL, record.getTargetid()).and("friendid",
                                    FilterExpress.EQUAL, record.getFromid())));
            if (exist) {
                return RetCodes.retResult(RetCodes.RET_FRIENDSHI_ALREADLY_IS_FIRIND);
            }
            return rs;
        }

        @Override
        public Class getContentClass() {
            return ContactNotificationMessage.class;
        }

        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            ContactNotificationMessage content = (ContactNotificationMessage) record.getContentObj();
            content.setFromUserId(record.getOperatorUserId());
            logger.finer("ContactNotificationHanler record=====>>>>>" + record);
            try {
                // 申请添加
                if (ContactNotificationMessage.OPERATION_REQ.equalsIgnoreCase(content.getOperation())) {
                    UserDetail userDetail = messageService.getSource().find(UserDetail.class, record.getFromid());
                    UserDetail friendDetail = messageService.getSource().find(UserDetail.class, record.getTargetid());
                    long syssetting = friendDetail.getSyssetting(); // 用户系统配置信息
                    // 第11位  表示需要验证  ，判断用户是否开启了好友验证,没开启就直接添加好友
                    if ((1024 & syssetting) == 1024) {
                        // 添加到申请表
                        long now = System.currentTimeMillis();
                        String friendaskid = record.getOperatorUserId() + "-" + content.getTargetUserId() + "-"
                                + Utility.format36time(System.currentTimeMillis());
                        FriendAsk ask = messageService.getSource().find(FriendAsk.class,
                                FilterNode.create("userid", FilterExpress.EQUAL, record.getOperatorUserId()).and("friendid",
                                        FilterExpress.EQUAL, content.getTargetUserId()));
                        if (ask == null) {
                            ask = new FriendAsk();
                            ask.setFriendaskid(friendaskid);
                            ask.setVerifymessage(content.getMessage());
                            ask.setFriendid(content.getTargetUserId());
                            ask.setInvitetype(content.getInvitetype());
                            ask.setCreatetime(now);
                            ask.setAnswer(FriendAsk.UNDO);
                            ask.setUserid(record.getOperatorUserId());
                            ask.setAskuserface(userDetail.getFace());
                            ask.setAskusername(userDetail.getUsername());
                            // 修改成队列操作 如果没有新增就直接
                            messageService.insertQueue.add(ask);
                        } else {
                            ask.setCreatetime(System.currentTimeMillis());
                            ask.setInvitetype(content.getInvitetype());
                            ask.setAnswer(FriendAsk.UNDO);
                            ask.setReadstatus(FriendAsk.UNREAD_STATUS);
                            messageService.getSource().updateColumn(ask, "createtime", "invitetype", "answer", "readstatus");
                        }
                        content.setFriendaskid(friendaskid);
                    } else {
                        long now = System.currentTimeMillis();
                        short invitetype = content.getInvitetype();
                        // todo 优化可删除answer 对象
                        RetResult result = bindFrinedShip(messageService, invitetype, content.getTargetUserId() > 0 ? content.getTargetUserId() : record.getTargetid(), record.getOperatorUserId(),
                                now);
                        logger.finest("添加好友结果===result ==" + jsonConvert.convertTo(result));
                        // 发送好友通知建立好友关系后弹出我们是好友了可以开始聊天
                        if (result.isSuccess()) {
                            BasicContent.TipMessage tipNotify = new BasicContent.TipMessage();
                            tipNotify.setType(BasicContent.TipMessage.USER_ADDFRIEND_TP);//添加好友
                            tipNotify.setContent(retInfo(record.getLocal(), FRIEND_BINDFRIEND));
                            String contentData = jsonConvert.convertTo(tipNotify);
                            MessageRecord tipRecordAsk = new MessageRecord();
                            tipRecordAsk.setMsgtype(BasicContent.TipMessage.TYPE);
                            tipRecordAsk.setFromid(record.getFromid());
                            tipRecordAsk.setTargetid(record.getTargetid());
                            tipRecordAsk.setContent(contentData);
                            tipRecordAsk.setMsgkind(MessageRecord.MSG_KIND_PRIVATE);
                            tipRecordAsk.setMessageid(record.getFromid() + "-" + record.getTargetid() + "-" + Utility.format36time(now));
                            tipRecordAsk.setCreatetime(now);

                            MessageRecord answer = new MessageRecord();
                            answer.setMsgtype(BasicContent.TipMessage.TYPE);
                            answer.setFromid(record.getTargetid());
                            answer.setTargetid(record.getFromid());
                            answer.setContent(contentData);
                            answer.setMsgkind(MessageRecord.MSG_KIND_PRIVATE);
                            answer.setMessageid(record.getTargetid() + "-" + record.getFromid() + "-" + Utility.format36time(now));
                            answer.setCreatetime(now);

                            // tip  消息保存
                            messageService.insertQueue.add(tipRecordAsk);
                            messageService.insertQueue.add(answer);
                            
                            messageService.updateQueue.add(() -> {
                            	int userid = record.getFromid();
                                int friendid  = record.getTargetid();
                                messageService.getSource().updateColumn(FriendAsk.class, FilterNode.create("userid", FilterExpress.EQUAL, userid)
                                			.and("friendid", FilterExpress.EQUAL, friendid), ColumnValue.mov("answer", FriendAsk.ACCEPT));
                                
                                messageService.getSource().updateColumn(FriendAsk.class, FilterNode.create("userid", FilterExpress.EQUAL, friendid)
                            				.and("friendid", FilterExpress.EQUAL, userid), ColumnValue.mov("answer", FriendAsk.ACCEPT));
                            });
                            
                            sendMessage(messageService, tipRecordAsk); // 发送tip消息
                            sendMessage(messageService, answer); // 发送tip消息
                            return feature; //不发送申请通知了
                        }
                        
                        
                    }
                }
                // 同意添加好友
                if (ContactNotificationMessage.OPERATION_ACCEPT_RSP.equalsIgnoreCase(content.getOperation())) {
                    // 更新好友关系
                    long now = System.currentTimeMillis();
                    short invitetype = content.getInvitetype();
                    // todo 优化可删除answer 对象
                    bindFrinedShip(messageService, invitetype, record.getOperatorUserId(), content.getTargetUserId(),
                            now);
                    String friendAskid = content.getFriendaskid();
                    FriendAsk ask = new FriendAsk();
                    ask.setFriendaskid(friendAskid);
                    ask.setAnswer(FriendAsk.ACCEPT);
                    
                    FriendAsk ask2 = new FriendAsk();
                    ask2.setFriendaskid(friendAskid);
                    ask2.setAnswer(FriendAsk.ACCEPT);
                    
                    
                    
                    messageService.updateQueue.add(() -> {
                    	int userid = record.getFromid();
                        int friendid  = record.getTargetid();
                        messageService.getSource().updateColumn(FriendAsk.class, FilterNode.create("userid", FilterExpress.EQUAL, userid)
                        			.and("friendid", FilterExpress.EQUAL, friendid), ColumnValue.mov("answer", FriendAsk.ACCEPT));
                        
                        messageService.getSource().updateColumn(FriendAsk.class, FilterNode.create("userid", FilterExpress.EQUAL, friendid)
                    				.and("friendid", FilterExpress.EQUAL, userid), ColumnValue.mov("answer", FriendAsk.ACCEPT));
                        
                        messageService.getSource().updateColumn(ask, "answer");
                    });
                    // 发送好友通知建立好友关系后弹出我们是好友了可以开始聊天
                    {
                        BasicContent.TipMessage tipNotify = new BasicContent.TipMessage();
                        tipNotify.setContent(retInfo(record.getLocal(), FRIEND_BINDFRIEND));
                        tipNotify.setType(BasicContent.TipMessage.USER_ADDFRIEND_TP);//添加好友
                        String contentData = jsonConvert.convertTo(tipNotify);
                        MessageRecord tipRecordAsk = new MessageRecord();
                        tipRecordAsk.setMsgtype(BasicContent.TipMessage.TYPE);
                        tipRecordAsk.setFromid(record.getFromid());
                        tipRecordAsk.setTargetid(record.getTargetid());
                        tipRecordAsk.setContent(contentData);
                        tipRecordAsk.setMsgkind(MessageRecord.MSG_KIND_PRIVATE);
                        tipRecordAsk.setMessageid(
                                record.getFromid() + "-" + record.getTargetid() + "-" + Utility.format36time(now));
                        tipRecordAsk.setCreatetime(now);

                        MessageRecord answer = new MessageRecord();
                        answer.setMsgtype(BasicContent.TipMessage.TYPE);
                        answer.setFromid(record.getTargetid());
                        answer.setTargetid(record.getFromid());
                        answer.setContent(contentData);
                        answer.setMsgkind(MessageRecord.MSG_KIND_PRIVATE);
                        answer.setMessageid(
                                record.getTargetid() + "-" + record.getFromid() + "-" + Utility.format36time(now));
                        answer.setCreatetime(now);

                        // tip  消息保存
                        messageService.insertQueue.add(tipRecordAsk);
                        messageService.insertQueue.add(answer);
                         
                        sendMessage(messageService, tipRecordAsk); // 发送tip消息
                        sendMessage(messageService, answer); // 发送tip消息
                    }
                }
                // 拒绝添加
                if (ContactNotificationMessage.OPERATION_REJECT_RSP.equalsIgnoreCase(content.getOperation())) {
                    // 更新好友关系
                    String friendAskid = content.getFriendaskid();
                    FriendAsk ask = new FriendAsk();
                    ask.setFriendaskid(friendAskid);
                    ask.setAnswer(FriendAsk.REJECT);
                    // 申请更新状态
                    messageService.updateQueue.add(() -> {
                        messageService.getSource().updateColumn(ask, "answer");
                    });

                }
                if (ContactNotificationMessage.OPERATION_IGNORE_RSP.equalsIgnoreCase(content.getOperation())) {
                    // 更新好友关系
                    long now = System.currentTimeMillis();
                    String friendAskid = content.getFriendaskid();
                    FriendAsk ask = new FriendAsk();
                    ask.setFriendaskid(friendAskid);
                    ask.setAnswer(FriendAsk.IGNORE);
                    // 申请更新状态
                    messageService.updateQueue.add(() -> {
                        messageService.getSource().updateColumn(ask, "answer");
                    });

                }
                record.setContent(jsonConvert.convertTo(record.getContentObj()));
                sendMessage(messageService, record);// 发送消息
                feature.complete(record);
            } catch (Throwable t) {
                feature.completeExceptionally(t);
            }
            return feature;
        }

        @Comment("绑定好友关系")
        private RetResult bindFrinedShip(MessageService messageService, short invitetype, int userId, int friendId, long now) {
            DataSource source = messageService.getSource();

            UserDetail answerUser = source.find(UserDetail.class, userId);
            UserDetail askUser = source.find(UserDetail.class, friendId);
            if (answerUser == null || askUser == null) {
                return RetCodes.retResult(RetCodes.RET_FRIENDSHI_BINDFRIENDSHIP_FAILED);// 绑定用户关系失败
            }
            FriendShip askFriendShip = new FriendShip();
            String askfriendshipid = userId + "-" + friendId;
            String answerfriendshipid = friendId + "-" + userId;

            askFriendShip.setCreatetime(now);
            askFriendShip.setUserid(userId);
            askFriendShip.setFriendid(friendId);
            //            askFriendShip.setFriendname(askUser.getUsername());
            askFriendShip.setFriendname("");
            askFriendShip.setInvitetype(invitetype);
            askFriendShip.setFriendshipid(askfriendshipid);

            FriendShip oldaskFriendShip = source.find(FriendShip.class, askfriendshipid);
            FriendShip oldanswerFriedShip = source.find(FriendShip.class, answerfriendshipid);
            if (oldaskFriendShip != null && oldanswerFriedShip != null) {
                return RetCodes.retResult(RetCodes.RET_FRIENDSHI_ALREADLY_IS_FIRIND);
            }
            FriendShip answerFriedShip = new FriendShip();
            answerFriedShip.setCreatetime(now);
            answerFriedShip.setUserid(friendId);
            answerFriedShip.setFriendid(userId);
            //            answerFriedShip.setFriendname(answerUser.getUsername());
            answerFriedShip.setFriendname("");
            answerFriedShip.setInvitetype(invitetype);
            answerFriedShip.setFriendshipid(answerfriendshipid);

            // 暂时 不用异步处理 保持 消息发送的先后顺序
            if (oldaskFriendShip == null) {
                source.insert(askFriendShip);
            }
            if (oldanswerFriedShip == null) {
                source.insert(answerFriedShip);
            }
            return RetResult.success();
        }

    }

    @Comment("已读通知")
    public static final class ReadReceiptHandler extends NotifyHandler {

        public static final MessageHandler instance = new ReadReceiptHandler();

        @Override
        public Class getContentClass() {
            return ReadReceiptMessage.class;
        }

        @Override
        protected RetResult validate(MessageService messageService, MessageRecord record) {
           RetResult rs = super.validate(messageService, record);
           if (!rs.isSuccess()) {
               return rs;
           }
            ReadReceiptMessage receiptMessage = (ReadReceiptMessage) record.getContentObj();
            if (receiptMessage == null || receiptMessage.getMessageId().isEmpty()) {
                return RetCodes.retResult(RetCodes.RET_PARAMS_ILLEGAL);
            }
            return RetResult.success();
        }

        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            try {
                DataSource source = messageService.getSource();
                ReadReceiptMessage content = (ReadReceiptMessage) record.getContentObj();
                String readMsgId = content.getMessageId();
                MessageRecord lastRecord = source.find(MessageRecord.class, readMsgId);
                // 更新消息状态为已读
                if (lastRecord != null) {
                    messageService.updateQueue.add(() -> {
                        // 用户创建时间小于等于最后一条消息的时间
                        FilterNode filterNode = FilterNode
                                .create("createtime", FilterExpress.LESSTHANOREQUALTO, lastRecord.getCreatetime())
                                .and("fromid", FilterExpress.EQUAL, lastRecord.getFromid())
                                .and("targetid", FilterExpress.EQUAL, lastRecord.getTargetid());

                        source.updateColumn(MessageRecord.class, filterNode,
                                ColumnValue.mov("status", MessageRecord.READ_STATUS),
                                ColumnValue.mov("readtime", System.currentTimeMillis()));
                        // 历史记录
                        source.updateColumn(MessageRecordHis.class, filterNode,
                                ColumnValue.mov("status", MessageRecord.READ_STATUS),
                                ColumnValue.mov("readtime", System.currentTimeMillis()));
                    });
                }
                sendMessage(messageService, record);// 发送消息
                feature.complete(record);
            } catch (Exception e) {
                feature.completeExceptionally(e);
            }
            return feature;
        }

    }

    public abstract static class GroupHandler extends NotifyHandler {

        @Comment("拉人入群")
        public RetResult pullUsersIntoGroup(MessageService messageService, int[] userIds, GroupDetail bean) {
            if (userIds.length == 0) {
                return RetCodes.retResult(RetCodes.RET_GROUP_PULL_USERS_EMPTY);
            }
            if (userIds.length > 0) {
                for (int userId : userIds) {
                    UserInfo user = messageService.getSource().find(UserInfo.class, userId);
                    join(messageService, user.getUserid(), user.getUsername(), bean);
                }
            }
            // 更新群人数
            refreshGroupUserNum(messageService, bean.getGroupid());
            return RetResult.success();
        }

        /**
         * 更新群人数
         *
         * @param groupId
         */
        protected int refreshGroupUserNum(MessageService messageService, int groupId) {
            Number numberResult = messageService.getSource().getNumberResult(UserGroup.class, FilterFunc.COUNT,
                    "groupid", FilterNode.create("groupid", FilterExpress.EQUAL, groupId));
            int intValue = numberResult.intValue();
            GroupDetail groupDetail = messageService.getSource().find(GroupDetail.class, groupId);
            // 更新群人数
            if (groupDetail != null) {
                groupDetail.setUsernum(intValue);
                messageService.getSource().update(groupDetail);
            }
            return intValue;
        }

        @Comment("加入群相关逻辑")
        public RetResult join(MessageService messageService, int userId, String userName, GroupDetail bean) {
            String userGroupid = bean.getGroupid() + "-" + userId;
            DataSource source = messageService.getSource();
            UserDetail userdetail = source.find(UserDetail.class, userId);
            UserGroup userGroup = source.find(UserGroup.class, userGroupid);
            // 已经加入群了不能再次加入
            if (userGroup != null) {
                return RetCodes.retResult(RetCodes.RET_GROUP_JOIN_FAILED_MEMBER_OF_GROUP);
            }
            // 用户不存在校验
            if (userdetail == null) {
                return RetCodes.retResult(RetCodes.RET_USER_NOTEXISTS);
            }
            userGroup = new UserGroup();
            userGroup.setUsergroupid(userGroupid);
            userGroup.setGroupid(bean.getGroupid());
            userGroup.setUserid(userdetail.getUserid());
            userGroup.setUsername(userdetail.getUsername());
            userGroup.setUsernickname(userdetail.getUsername());
            userGroup.setFace(userdetail.getFace());
            userGroup.setJointime(System.currentTimeMillis());
            // 如果是匿名群就添加索引
			//            if (bean.getGrouptype() == GroupDetail.GROUP_TYPE_ANONYMOUS) {
			//                int annoyindex = source
			//                        .getNumberResult(UserGroup.class, FilterFunc.MAX, 0, "annoyindex",
			//                                FilterNode.create("usergroupid", FilterExpress.EQUAL, bean.getGroupid()))
			//                        .intValue() + 1;
			//                userGroup.setAnnoyindex(annoyindex);
			//            }
            
            int annoyindex = source
                    .getNumberResult(UserGroup.class, FilterFunc.MAX, 0, "annoyindex",
                            FilterNode.create("usergroupid", FilterExpress.EQUAL, bean.getGroupid()))
                    .intValue() + 1;
            userGroup.setAnnoyindex(annoyindex);
            
            source.insert(userGroup);
            return RetResult.success(userGroup);
        }

        @Comment("更新群名称")
        public RetResult updateGroupName(DataSource source, int currentUserid, GroupDetail bean) {
            GroupDetail detail = source.find(GroupDetail.class, FilterNode.create("groupid", FilterExpress.EQUAL, bean.getGroupid()));
            if (detail != null) {
                source.updateColumn(GroupDetail.class, bean.getGroupid(), "groupname", bean.getGroupname());
                source.updateColumn(UserGroup.class,
                        FilterNode.create("groupid", FilterExpress.EQUAL, bean.getGroupid()),
                        ColumnValue.mov("groupname", detail.getGroupname()));
            } else {
                return RetCodes.retResult(RetCodes.RET_RONGCLOUD_UPDATE_GROUP_ERROR);
            }
            return RetResult.success();
        }

        @Comment("跟新通知")
        public RetResult updateGroupNotice(DataSource source, int currentUserid, GroupDetail bean) {
            GroupDetail detail = source.find(GroupDetail.class,
                    FilterNode.create("groupid", FilterExpress.EQUAL, bean.getGroupid()).and("createuserid",
                            FilterExpress.EQUAL, currentUserid));
            if (detail != null) {
                source.updateColumn(GroupDetail.class, bean.getGroupid(), "groupnotice", bean.getGroupnotice());
            } else {
                return RetCodes.retResult(RetCodes.RET_RONGCLOUD_UPDATE_GROUP_ERROR);
            }
            return RetResult.success();
        }

        @Comment("踢人出群")
        protected RetResult kickUserFromGroup(MessageService messageService, int currentUser, int[] userIds,
                int groupId) {
            DataSource source = messageService.getSource();
            GroupDetail groupDetail = source.find(GroupDetail.class, groupId);
            RetResult result = null;
            // 群不存在
            if (groupDetail == null) {
                return RetCodes.retResult(RetCodes.RET_GROUP_UNEXIST);
            }
            int createuserid = groupDetail.getCreateuserid();
            // 非群主无踢人权限
            if (createuserid != currentUser) {
                return RetCodes.retResult(RetCodes.RET_GROUP_INVALID_PERMISSION);
            }
            // 剔除用户信息
            for (int index = 0; index < userIds.length; index++) {
                int kickUserId = userIds[index];
                if (createuserid == kickUserId) {
                    return RetCodes.retResult(RetCodes.RET_GROUP_KICK_MEMBER_IS_GROUP_OWNER);
                }
                UserInfo kickUser = source.find(UserInfo.class, kickUserId);
                if (kickUser == null) {
                    return RetCodes.retResult(RetCodes.RET_USER_NOTEXIT_FIRIND);
                }
                String userGroupId = groupId + "-" + kickUserId;
                UserGroup userGroup = source.find(UserGroup.class, userGroupId);
                if (userGroup != null) {
                    messageService.insertQueue.add(userGroup.createTableHis(System.currentTimeMillis())); //删除记录添加
                    source.delete(UserGroup.class, userGroupId);
                }

            }
             updateGroupFace(messageService, groupDetail);//更新群头像
            // 更新群人数
            return result;
        }

        @Comment("主动退出群组")
        public RetResult<UserGroup> quitGroup(MessageService messageService, int userId, int groupId,
                int newCreatorId) {
            String userGroupId = groupId + "-" + userId;
            DataSource source = messageService.getSource();
            // 先发通知在退出群
            com.cratos.xxgram.platf.rongcloud.NotifyContent.GroupNotificationMessage.QuitGroup quitGroupMsg = new com.cratos.xxgram.platf.rongcloud.NotifyContent.GroupNotificationMessage.QuitGroup();
            GroupDetail groupDetail = source.find(GroupDetail.class, groupId);
            int createuserid = groupDetail.getCreateuserid();
            boolean isManage = createuserid == userId;
            // 群主退群
            UserGroup creatorGroup = null;
            if (isManage) {
                String usergroupid = groupId + "-" + newCreatorId;
                creatorGroup = source.find(UserGroup.class, usergroupid);
                // 管理员用户不存在
                if (creatorGroup == null) {
                    return RetCodes.retResult(RetCodes.RET_CREATOR_USER_NOTEXIT_FIRIND);
                }
                if (newCreatorId == userId) {
                    return RetCodes.retResult(RetCodes.RET_UPDATE_CREATOR_FIRIND);
                }
                quitGroupMsg.setNewCreatorId(Integer.toString(newCreatorId, 36));
                groupDetail.setCreateuserid(newCreatorId);
                source.update(groupDetail);// 更新群主信息
            }

            UserGroup userGroup = source.find(UserGroup.class, userGroupId);
            if (userGroup != null) {
                source.delete(UserGroup.class, userGroupId);
                messageService.insertQueue.add(userGroup.createTableHis(System.currentTimeMillis())); //删除记录添加
                // 更新群人数
                updateGroupFace(messageService, groupDetail);//更新群头像
                refreshGroupUserNum(messageService, groupId);
            }
            return RetResult.success(creatorGroup);
        }

        public static final Cryptos.ECDHCrypto ecdhCrypto = Cryptos.ECDHCrypto.getInstance();

        @Comment("更新群头像")
        protected void updateGroupFace(MessageService service, GroupDetail bean)  {
            // if (bean.getGrouptype() == GroupDetail.GROUP_TYPE_NORMAL) 
            {
                try {
                    DataSource source = service.getSource();
                    Flipper flipper = new Flipper(9, "jointime desc");
                    List<String> userfaces = source.queryColumnList("face", UserGroup.class, flipper, FilterNode.create("groupid", FilterExpress.EQUAL, bean.getGroupid()));
                    String groupface = service.getFileService().storeGroupImage(Integer.toString(bean.getGroupid(), 36) + "-" + Long.toString(bean.getCreatetime(), 36), userfaces);
                    bean.setGroupface(groupface);
                    source.updateColumn(bean, "groupface");// 更新群头像
                } catch (IOException ex) {
                    Logger.getLogger(NotifyHandler.class.getName()).log(Level.SEVERE, null, ex);
                }
            }
        }
        
        @Comment("创建修改群组")
        public RetResult<GroupDetail> createGroup(MessageService messageService, int currentUserId, GroupDetail bean,
                final Integer[] userIds) throws Exception {
            DataSource source = messageService.getSource();
            // 群名称不能为空
            if ("".equals(bean.getGroupname()) || null == bean.getGroupname()) {
                return RetCodes.retResult(RetCodes.RET_GROUP_NAME_EMPTY);
            }
            //            int groupid = source
            //                    .getNumberResult(GroupDetail.class, FilterFunc.MAX, 1_0000_0000, "groupid", (FilterNode) null)
            //                    .intValue() + 1;
            int groupid = 1_0000_0000 + idRandom.nextInt(500_0000);//随机生成群id
            bean.setGroupid(groupid);
            bean.setCreatetime(System.currentTimeMillis());
            bean.setCreateuserid(currentUserId);
            // ECDH 更新私钥公钥
            {
                KeyPair keyPair = ecdhCrypto.generateKeyPairNamedCurve(Cryptos.ECParams.secp160k1Key);
                PrivateKey privateKey = keyPair.getPrivate(); // 私钥
                PublicKey publicKey = keyPair.getPublic(); // 公钥
                String privateKeyStr = Base64.getEncoder().encodeToString(privateKey.getEncoded());
                String publicKeyStr = Base64.getEncoder().encodeToString(publicKey.getEncoded());
                bean.setEcdhprivkey(privateKeyStr);
                bean.setEcdhpubkey(publicKeyStr);
            }
            source.insert(bean);// 保存群信息
            List<String> userfaces = new java.util.ArrayList();
            UserInfo userInfo = source.find(UserInfo.class, currentUserId);
            join(messageService, userInfo.getUserid(), userInfo.getUsername(), bean); // 群主加群
            userfaces.add(userInfo.getFace());
            if (userIds != null) {
                for (int id : userIds) {
                    UserInfo user = source.find(UserInfo.class, id);
                    if (user == null) {
                        logger.finest("user is null " + id);
                        continue;
                    }
                    join(messageService, user.getUserid(), user.getUsername(), bean);
                    if (userfaces.size() < 9) {
                        userfaces.add(user.getFace()); // 子添加前9个用户头像
                    }
                }
            }
            //  if (bean.getGrouptype() == GroupDetail.GROUP_TYPE_NORMAL)
            {
                // 生成群头像名称
                String groupface = messageService.getFileService().storeGroupImage(
                        Integer.toString(groupid, 36) + "-" + Long.toString(bean.getCreatetime(), 36), userfaces);
                bean.setGroupface(groupface);
            }

            source.updateColumn(bean, "groupface");// 更新群头像
            // 更新群人数
            bean.setUsernum(refreshGroupUserNum(messageService, bean.getGroupid()));
            return RetResult.success(bean);
        }

        @Comment("修改聊天背景")
        public RetResult updateChatBackGround(MessageService messageService, UserGroup bean) {
            messageService.getSource().updateColumn(UserGroup.class, bean.getUsergroupid(), "chatbackground",
                    bean.getChatbackground());
            return RetResult.success();
        }

        @Comment("更新用户群昵称")
        public RetResult updateUserGroupName(MessageService messageService, int currentUserId, UserGroup userGroup) {
            DataSource source = messageService.getSource();
            int groupId = userGroup.getGroupid();
            int userId = userGroup.getUserid();
            if (userId != currentUserId) {
                GroupDetail groupDetail = source.find(GroupDetail.class, groupId);
                if (groupDetail == null) {
                    return RetCodes.retResult(RetCodes.RET_GROUP_UNEXIST);
                }
                if (currentUserId != groupDetail.getCreateuserid()) {
                    return RetCodes.retResult(RetCodes.RET_RONGCLOUD_UPDATENICKNAME_INVALID_PERMISSION);
                }
            }
            userGroup.setUsergroupid(groupId + "-" + userId);
            userGroup.setUsernickname(userGroup.getUsernickname());
            source.updateColumn(userGroup, "usernickname");
            return RetResult.success();
        }

        public RetResult updateSystemSetting(MessageService messageService, MessageRecord record, int groupid, int index, int value) {
            DataSource source = messageService.getSource();
            int userid = record.getFromid();
            String usergroupId = groupid + "-" + userid;

            UserGroup userGroup = source.find(UserGroup.class, usergroupId);
            GroupDetail groupDetail = source.find(GroupDetail.class, groupid);
            if (userGroup == null || groupDetail == null) {
                return RetCodes.retResult(RetCodes.RET_RONGCLOUD_UPDATE_GROUP_ERROR);
            }
            // 群组权限 只有群组才能禁言 设置匿名群
            if (index < UserGroup.SYSSETTING_GROUP_LIMIT_INDEX) {
                // 校验是不是管理员
                if (groupDetail.getCreateuserid() != userid) {
                    return RetCodes.retResult(RetCodes.RET_RONGCLOUD_GROUP_INVALID_PERMISSION);
                }
                long oldVal = groupDetail.getSyssetting();
                long decVal = (long) Math.pow(2, (index - 1));
                long yuVal = 0xFFFFFFFF - decVal;
                long cValue = yuVal & oldVal;//减少  当前位的值  获得其他位数的值
                // 判断当前位数的值是否需要增加
                if (value == 1) {
                    cValue = cValue + decVal;
                }
                //更新群信息
                source.updateColumnAsync(GroupDetail.class, groupDetail.getGroupid(), ColumnValue.mov("syssetting", cValue)).whenComplete((o, r) -> {
                    if (r == null) {
                        source.queryListAsync(UserGroup.class, FilterNode.create("groupid", FilterExpress.EQUAL, groupid)).whenComplete((dataList, error) -> {
                            if (error != null) {
                                logger.finest("updateSystemSetting error ....." + error.getMessage());
                                return;
                            }
                            dataList.forEach(obj -> updateSystemSetting(messageService, obj.getUserid(), obj.getGroupid(), index, value));
                        });
                    }
                }).join();
            }
            // 更新自己的配置
            return updateSystemSetting(messageService, userid, groupid, index, value);
        }

        @Comment("更新群状态")
        private RetResult updateSystemSetting(MessageService messageService, int userId, int groupId, int index, int value) {
            DataSource source = messageService.getSource();
            String usergroupId = groupId + "-" + userId;
            UserGroup userGroup = source.find(UserGroup.class, usergroupId);
            if (userGroup == null) {
                return RetCodes.retResult(RetCodes.RET_FRIENDSHI_FRIENDINFO_NOTEXIT_FIRIND);
            }
            long oldVal = userGroup.getSyssetting();
            //  long decVal = ((index - 1) == 0) ? 1 : (index - 1) << 2;
            index = (index - 1);
            long decVal = (long) Math.pow(2, index);
            long yuVal = 0xFFFFFFFF - decVal;
            long cValue = yuVal & oldVal;//减少  当前位的值  获得其他位数的值
            // 判断当前位数的值是否需要增加
            if (value == 1) {
                cValue = cValue + decVal;
            }
            source.updateColumn(UserGroup.class, usergroupId, ColumnValue.mov("syssetting", cValue));
            //更新字段值
            return RetResult.success(cValue);
        }
    }

    @Comment("新建群")
    public static final class CreateGroupHandler extends GroupHandler {

        public static final MessageHandler instance = new CreateGroupHandler();

        @Override
        @Comment("校验")
        protected RetResult validate(MessageService messageService, MessageRecord record) {
            // TODO Auto-generated method stub
        	CreateGroupNotify createGroup = (CreateGroupNotify) record.getContentObj();
        	String groupName = createGroup.getTargetGroupName();
        	// 校验群名称是否合法
        	if (groupName.isBlank() || groupName.length() > GroupDetail.GROUPNAME_MAXLEN) {
        		return RetCodes.retResult(RetCodes.RET_GROUP_INVALID_GROUPNAME);
        	}
        	return super.validate(messageService, record);
        }

        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            try {
                CreateGroupNotify create = (CreateGroupNotify) record.getContentObj();
                String groupName = create.getTargetGroupName();
                GroupDetail groupDetail = new GroupDetail();
                groupDetail.setGroupname(groupName);
                groupDetail.setCreateuserid(record.getOperatorUserId());
                groupDetail.setGrouptype(create.getGrouptype());
                // 创建群组
                RetResult<GroupDetail> rs = createGroup(messageService, record.getOperatorUserId(), groupDetail,
                        create.getUserIds());
                // sendMessage(messageService, record);//发送消息
                // 通知每个用户创建群成功!!
                if (rs.isSuccess()) {
                    groupDetail = rs.getResult();
                    BasicContent.TipMessage tipMessage = new BasicContent.TipMessage();
                    tipMessage.setType(BasicContent.TipMessage.GROUP_CREATEGROUP_TP);//创建群
                    tipMessage.setContent(retInfo(record.getLocal(), GROUP_CREATE));
                    tipMessage.setExtra(rs.getResult());
                    {
                        long now = System.currentTimeMillis();
                        MessageRecord tipRecord = new MessageRecord();
                        tipRecord.setMsgtype(BasicContent.TipMessage.TYPE);
                        tipRecord.setFromid(record.getFromid());
                        tipRecord.setContent(jsonConvert.convertTo(tipMessage));
                        tipRecord.setMsgkind(MessageRecord.MSG_KIND_GROUP);// 群发
                        tipRecord.setMessageid(
                                record.getTargetid() + "-" + record.getFromid() + "-" + Utility.format36time(now));
                        tipRecord.setCreatetime(now);
                        tipRecord.setTargetid(groupDetail.getGroupid());
                        // 群发给 被拉进群的用户
                        sendMessage(messageService, tipRecord);
                        // tip  消息保存
                        messageService.insertQueue.add(tipRecord);
                    }
                } else {
                    throw new RuntimeException("create group error !!");
                }
                feature.complete(record);
            } catch (Exception e) {
                feature.completeExceptionally(e);
            }
            return feature;
        }

        @Override
        public Class getContentClass() {
            return CreateGroupNotify.class;
        }

        @Comment("更新用户群昵称")
        public RetResult updateUserGroupName(MessageService messageService, int currentUserId, UserGroup userGroup) {
            DataSource source = messageService.getSource();
            int groupId = userGroup.getGroupid();
            int userId = userGroup.getUserid();
            if (userId != currentUserId) {
                GroupDetail groupDetail = source.find(GroupDetail.class, groupId);
                if (groupDetail == null) {
                    return RetCodes.retResult(RetCodes.RET_GROUP_UNEXIST);
                }
                if (currentUserId != groupDetail.getCreateuserid()) {
                    return RetCodes.retResult(RetCodes.RET_RONGCLOUD_UPDATENICKNAME_INVALID_PERMISSION);
                }
            }
            userGroup.setUsergroupid(groupId + "-" + userId);
            userGroup.setUsernickname(userGroup.getUsernickname());
            source.updateColumn(userGroup, "usernickname");//更新用户群昵称
            return RetResult.success();
        }

    }

    @Comment("更新群公告群名称")
    public static final class UpdateGroupHandler extends GroupHandler {

        public static final MessageHandler instance = new UpdateGroupHandler();

        @Override
        protected RetResult validate(MessageService messageService, MessageRecord record) {
           UpdateGroupNotify groupNotify = (UpdateGroupNotify) record.getContentObj();
           int groupId = groupNotify.getGroupId();
           DataSource source = messageService.getSource();
           if (UpdateGroupNotify.UPDATE_NOTICE == groupNotify.getOpType()) {
               GroupDetail detail = source.find(GroupDetail.class,
               FilterNode.create("groupid", FilterExpress.EQUAL, groupId).and("createuserid", FilterExpress.EQUAL, record.getFromid()));
            if (detail == null) {
                return RetCodes.retResult(RetCodes.RET_RONGCLOUD_UPDATE_GROUP_ERROR);
            } 
           }
           // 群名校验
           if (UpdateGroupNotify.UPDATE_GROUP_NAME == groupNotify.getOpType()) {
        	   String groupName = groupNotify.getGroupName();
	    	   // 校验群名称是否合法
	           if (groupName.isBlank() || groupName.length() > GroupDetail.GROUPNAME_MAXLEN) {
	          		return RetCodes.retResult(RetCodes.RET_GROUP_INVALID_GROUPNAME);
	           }
           }
           return super.validate(messageService, record); //To change body of generated methods, choose Tools | Templates.
        }

        
        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            try {
                UpdateGroupNotify content = (UpdateGroupNotify) record.getContentObj();
                GroupDetail bean = new GroupDetail();
                BasicContent.TipMessage tipMessage = new BasicContent.TipMessage();
                bean.setGroupid(content.getGroupId());
                String desc = "";
                if (UpdateGroupNotify.UPDATE_GROUP_NAME == content.getOpType()) {
                    bean.setGroupname(content.getGroupName());
                    tipMessage.setType(BasicContent.TipMessage.GROUP_UPDATE_NAME_TP);//群名称更新
                    desc = retInfo(record.getLocal(), GROUP_UPDATENAME);
                    RetResult rs = updateGroupName(messageService.getSource(), record.getOperatorUserId(), bean);
                    if (rs.isSuccess()) {
                        tipMessage.setContent(desc);
                        tipMessage.setExtra(bean);
                       {
                        MessageRecord tipRecord = new MessageRecord(); 
                        long now = System.currentTimeMillis();
                        tipRecord.setMsgtype(BasicContent.TipMessage.TYPE);
                        tipRecord.setFromid(record.getFromid());
                        tipRecord.setContent(jsonConvert.convertTo(tipMessage));
                        tipRecord.setMsgkind(MessageRecord.MSG_KIND_GROUP);// 群发
                        tipRecord.setMessageid(record.getTargetid() + "-" + record.getFromid() + "-" + Utility.format36time(now));
                        tipRecord.setCreatetime(now);
                        tipRecord.setTargetid(bean.getGroupid());
                        // 群发给 被拉进群的用户
                        sendMessage(messageService, tipRecord);
                        // tip  消息保存
                        messageService.insertQueue.add(tipRecord);
                       }
                    }
                }
                
                if (UpdateGroupNotify.UPDATE_NOTICE == content.getOpType()) {
                    desc = retInfo(record.getLocal(), GROUP_UPDATENOTICE);
                    TextMessage text = new TextMessage(content.getGroupNotice());
                    text.setMentionedInfo(MentionedInfo.from(null, MentionedInfo.ALL));
                    bean.setGroupnotice(content.getGroupNotice());
                    RetResult rsnotice = updateGroupNotice(messageService.getSource(), record.getOperatorUserId(), bean);
                    if (rsnotice.isSuccess()) {
                    	text.setContent(content.getGroupNotice());
                    	text.setExtra(record);
                       {
                        MessageRecord recordcontent = new MessageRecord(); 
                        long now = System.currentTimeMillis();
                        recordcontent.setMsgtype(BasicContent.TextMessage.TYPE);
                        recordcontent.setFromid(record.getFromid());
                        recordcontent.setContent(jsonConvert.convertTo(text));
                        recordcontent.setMsgkind(MessageRecord.MSG_KIND_GROUP);// 群发
                        recordcontent.setMessageid(record.getFromid() + "-" + content.getGroupId() + "-" + Utility.format36time(now));
                        recordcontent.setCreatetime(now);
                        recordcontent.setTargetid(bean.getGroupid());
                        // 群发给 被拉进群的用户
                        sendMessage(messageService, recordcontent);
                        sendNotifyMessageWithSave( messageService,  recordcontent, Arrays.asList(record.getFromid()));//给自己发
                        // tip  消息保存
                        messageService.insertQueue.add(recordcontent);
                       }
                    }
                }
                feature.complete(record);
            } catch (Exception e) {
                e.printStackTrace();
                feature.completeExceptionally(e);
            }

            return feature;
        }

        @Override
        public Class getContentClass() {
            return UpdateGroupNotify.class;
        }

    }

    @Comment("加入群")
    public static final class AddMemberToGroupHandler extends GroupHandler {

        public static final MessageHandler instance = new AddMemberToGroupHandler();

        @Override
        protected RetResult validate(MessageService messageService, MessageRecord record) {
            return super.validate(messageService, record); //To change body of generated methods, choose Tools | Templates.
        }

        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            try {
                feature.complete(record);
                AddMemberToGroupNotify content = (AddMemberToGroupNotify) record.getContentObj();
                GroupDetail group = messageService.getSource().find(GroupDetail.class, content.getGroupId());
                if (group == null) {
                    logger.warning("group is null.....");
                }
                int[] targetUserIds = content.getTargetUserIds();
                if (content.getJoinType() == AddMemberToGroupNotify.PULL_BY_OTHER) {
                    RetResult result = pullUsersIntoGroup(messageService, targetUserIds, group);
                    // 如果已经添加过了就不用重复添加发送消息
                    logger.info("AddMemberToGroupHandler error ,result==" + jsonConvert.convertTo(result) + ", targetUserIds =" + jsonConvert.convertTo(targetUserIds) + ", group ==" + jsonConvert.convertTo(group));
                    if (!result.isSuccess()) {
                        return feature;
                    }
                    updateGroupFace(messageService, group);//更新群头像
                }
                if (content.getJoinType() == AddMemberToGroupNotify.JOIN_BY_OWNER) {
                    RetResult result = join(messageService, record.getOperatorUserId(), record.getOperatorUserName(),
                            group);
                    updateGroupFace(messageService, group);//更新群头像
                    logger.info("AddMemberToGroupHandler error ,result==" + jsonConvert.convertTo(result) + ", targetUserIds =" + jsonConvert.convertTo(targetUserIds) + ", group ==" + jsonConvert.convertTo(group));
                    // 如果已经添加过了就不用重复添加发送消息
                    if (!result.isSuccess()) {
                        return feature;
                    }
                }
                // 群聊通知
                BasicContent.TipMessage tipMessage = new BasicContent.TipMessage();
                tipMessage.setTargetUserids(targetUserIds);
                tipMessage.setType(BasicContent.TipMessage.GROUP_JOINGROUP_TP);//主动加群
                group.setUsernum(refreshGroupUserNum(messageService, group.getGroupid()));
                tipMessage.setExtra(group);
                tipMessage.setContent(String.join(",", content.getTargetUserNames()) + retInfo(record.getLocal(), GROUP_JOIN));
                {
                    long now = System.currentTimeMillis();
                    MessageRecord tipRecord = new MessageRecord();
                    tipRecord.setMsgtype(BasicContent.TipMessage.TYPE);
                    tipRecord.setFromid(record.getFromid());
                    tipRecord.setContent(jsonConvert.convertTo(tipMessage));
                    tipRecord.setMsgkind(MessageRecord.MSG_KIND_GROUP);// 群发
                    tipRecord.setMessageid(record.getFromid() + "-" + content.getGroupId() + "-" + Utility.format36time(now));
                    tipRecord.setCreatetime(now);
                    tipRecord.setTargetid(group.getGroupid());
                    // tip  消息保存
                    messageService.insertQueue.add(tipRecord);
                    // 群发给 被拉进群的用户
                    sendMessage(messageService, tipRecord);
                  
                }
                // 查询当前群有多少用户在进行对其进行信息推送
            } catch (Exception e) {
                feature.completeExceptionally(e);
            }

            return feature;
        }

        @Override
        public Class getContentClass() {
            return AddMemberToGroupNotify.class;
        }

    }

    @Comment("踢人出群")
    public static final class KickedGroupHandler extends GroupHandler {

        public static final MessageHandler instance = new KickedGroupHandler();

        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            try {
                feature.complete(record);
                KickedGroupNotify content = (KickedGroupNotify) record.getContentObj();
                int[] userIds = content.getTargetUserIds();
                List<UserGroup> receiverUsers = messageService.getSource().queryList(UserGroup.class, FilterNode.create("groupid", FilterExpress.EQUAL, content.getGroupId()));
                // 踢人出群
                RetResult retResult = kickUserFromGroup(messageService, record.getOperatorUserId(), userIds,
                        content.getGroupId());
                logger.finest("KickedGroupHandler retResult ===>>>>>>" + retResult);
                // 踢出群聊通知
                BasicContent.TipMessage tipMessage = new BasicContent.TipMessage();
                tipMessage.setType(BasicContent.TipMessage.GROUP_KICKGROUP_TP);//提出群提示
                tipMessage.setContent(String.join(",", content.getTargetUserNames()) + retInfo(record.getLocal(), GROUP_KICK));
                tipMessage.setExtra(content);
                {
                    long now = System.currentTimeMillis();
                    MessageRecord tipRecord = new MessageRecord();
                    tipRecord.setMsgtype(BasicContent.TipMessage.TYPE);
                    tipRecord.setFromid(record.getFromid());
                    tipRecord.setTargetid(content.getGroupId());
                    tipRecord.setContent(jsonConvert.convertTo(tipMessage));
                    tipRecord.setMsgkind(MessageRecord.MSG_KIND_GROUP);// 群发
                    tipRecord.setMessageid(record.getFromid() + "-" + content.getGroupId() + "-" + Utility.format36time(now));
                    tipRecord.setCreatetime(now);
                    tipRecord.setTargetid(content.getGroupId());
                    // 群发给 被拉进群的用户
                    logger.finest("rec grouduser " + jsonConvert.convertTo(receiverUsers));
                    // 通知带保存消息
                    if (receiverUsers != null) {
                        Set<Integer> userids = receiverUsers.stream().map(UserGroup::getUserid).collect(Collectors.toSet());
                        sendNotifyMessageWithSave(messageService, tipRecord, userids);// 群发给群用户
                    }
                     // tip  消息保存
                    messageService.insertQueue.add(tipRecord);
                   
                }

            } catch (Exception e) {
                feature.completeExceptionally(e);
            }
            return feature;
        }

        @Override
        public Class getContentClass() {
            return KickedGroupNotify.class;
        }

    }

    @Comment("退出群")
    public static final class QuitGroupHandler extends GroupHandler {

        public static final MessageHandler instance = new QuitGroupHandler();

        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            try {
                QuitGroupNotify content = (QuitGroupNotify) record.getContentObj();
                // 退出群组
                RetResult rs = quitGroup(messageService, record.getOperatorUserId(), content.getGroupId(), content.getNewCreatorId());
                if (rs.isSuccess()) {
                    // 踢出群聊通知
                    BasicContent.TipMessage tipMessage = new BasicContent.TipMessage();
                    tipMessage.setType(BasicContent.TipMessage.GROUP_QUITGROUP_TP);//退出群提示
                    tipMessage.setContent(record.getOperatorUserName() + retInfo(record.getLocal(), GROUP_QUIT));
                    DataSource source = messageService.getSource();
                    GroupDetail group = source.find(GroupDetail.class, content.getGroupId());
                    if (group.isAnonymousGroup()) {
                    	 tipMessage.setContent("*****" + retInfo(record.getLocal(), GROUP_QUIT));
                    }
                   
                    tipMessage.setExtra(content); // 返回群信息
                    {
                        long now = System.currentTimeMillis();
                        MessageRecord tipRecord = new MessageRecord();
                        tipRecord.setMsgtype(BasicContent.TipMessage.TYPE);
                        tipRecord.setFromid(record.getFromid());
                        tipRecord.setContent(jsonConvert.convertTo(tipMessage));
                        tipRecord.setMsgkind(MessageRecord.MSG_KIND_GROUP);// 群发
                        tipRecord.setMessageid(record.getTargetid() + "-" + record.getFromid() + "-" + Utility.format36time(now));
                        tipRecord.setCreatetime(now);
                        tipRecord.setTargetid(content.getGroupId());
                        // 同步发送群发给 被拉进群的用户
                        List<UserGroup> receiverUsers = messageService.getSource().queryList(UserGroup.class, FilterNode.create("groupid", FilterExpress.EQUAL, content.getGroupId()));
                        logger.finest("rec grouduser " + jsonConvert.convertTo(receiverUsers));
                        // 通知带保存消息
                        if (receiverUsers != null) {
                            Set<Integer> userids = receiverUsers.stream().map(UserGroup::getUserid).collect(Collectors.toSet());
                            userids.add(record.getFromid());
                            messageService.insertQueue.add(tipRecord); // 保存数据库
                            sendNotifyMessageWithSave(messageService, tipRecord, userids);// 群发给群用户
                        }
                    }
                }
                feature.complete(record);
            } catch (Exception e) {
                feature.completeExceptionally(e);
            }
            return feature;
        }

        @Override
        public Class getContentClass() {
            return QuitGroupNotify.class;
        }

    }

    @Comment("解散群")
    public static final class DissMissGroupHandler extends GroupHandler {

        public static final MessageHandler instance = new DissMissGroupHandler();

        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            try {
                DissMissGroupNotify content = (DissMissGroupNotify) record.getContentObj();
                DataSource source = messageService.getSource();
                GroupDetail group = source.find(GroupDetail.class,
                        FilterNode.create("groupid", FilterExpress.EQUAL, content.getGroupId()).and("createuserid",
                                FilterExpress.EQUAL, record.getFromid()));
                if (group != null) {
                    // 解散群通知
                    BasicContent.TipMessage tipMessage = new BasicContent.TipMessage();
                    tipMessage.setType(BasicContent.TipMessage.GROUP_DISMISSGROUP_TP);
                    tipMessage.setExtra(group);
                    //群解散
                    tipMessage.setContent(retInfo(record.getLocal(), GROUP_DISMISS));
                    {
                        long now = System.currentTimeMillis();
                        MessageRecord tipRecord = new MessageRecord();
                        tipRecord.setMsgtype(BasicContent.TipMessage.TYPE);
                        tipRecord.setFromid(record.getFromid());
                        tipRecord.setTargetid(content.getGroupId());
                        tipRecord.setContent(jsonConvert.convertTo(tipMessage));
                        tipRecord.setMsgkind(MessageRecord.MSG_KIND_GROUP);// 群发
                        tipRecord.setMessageid(
                                record.getTargetid() + "-" + record.getFromid() + "-" + Utility.format36time(now));
                        tipRecord.setCreatetime(now);
                        tipRecord.setTargetid(content.getGroupId());
                        // 同步发送群发给 被拉进群的用户
                        List<UserGroup> receiverUsers = source.queryList(UserGroup.class, FilterNode.create("groupid", FilterExpress.EQUAL, group.getGroupid()));
                        logger.finest("rec grouduser " + jsonConvert.convertTo(receiverUsers));
                        // 通知带保存消息
                        if (receiverUsers != null) {
                            Set<Integer> userids = receiverUsers.stream().map(UserGroup::getUserid).collect(Collectors.toSet());
                             messageService.insertQueue.add(tipRecord); // 保存数据库
                            sendNotifyMessageWithSave(messageService, tipRecord, userids);// 群发给群用户
                        }
                        // 处理解散群业务逻辑
                        RetResult result = dismissGroup(messageService, record.getOperatorUserId(), content.getGroupId());
                        logger.finest("群解散结果====>>>" + jsonConvert.convertTo(result));
                    }
                }
                feature.complete(record);
            } catch (Exception e) {
                feature.completeExceptionally(e);
            }
            return feature;
        }

        @Comment("解散群")
        public RetResult dismissGroup(MessageService messageService, int currentUserId, int groupId) {
            DataSource source = messageService.getSource();
            GroupDetail group = source.find(GroupDetail.class,
                    FilterNode.create("groupid", FilterExpress.EQUAL, groupId).and("createuserid", FilterExpress.EQUAL,
                            currentUserId));
            if (group != null) {
                List<UserGroup> list = source.queryList(UserGroup.class, FilterNode.create("groupid", FilterExpress.EQUAL, groupId));
                long now = System.currentTimeMillis();
                if (list != null && list.size() > 0) {
                    list.forEach(usergroup -> {
                        messageService.insertQueue.add(usergroup.createTableHis(now));
                    });
                }
                messageService.insertQueue.add(group.createTableHis(now));//新增群删除记录
                source.delete(UserGroup.class, FilterNode.create("groupid", FilterExpress.EQUAL, groupId)); // 清除群记录
                source.delete(GroupDetail.class, groupId); // 删除群信息
            } else {
                return RetCodes.retResult(RetCodes.RET_GROUP_DISMISS_FAILED);
            }
            return RetResult.success();
        }

        @Override
        public Class getContentClass() {
            return DissMissGroupNotify.class;
        }

    }

    @Comment("更新用户群昵称")
    public static final class UpdateUserGroupNameHanler extends GroupHandler {

        public static final MessageHandler instance = new UpdateUserGroupNameHanler();

        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            try {
                UpdateUserGroupNameNotify content = (UpdateUserGroupNameNotify) record.getContentObj();
                UserGroup userGroup = new UserGroup();
                userGroup.setGroupid(content.getGroupId());
                userGroup.setUserid(record.getFromid());
                userGroup.setUsername(record.getOperatorUserName());
                userGroup.setUsernickname(content.getUserNickName());
                userGroup.setChatbackground(content.getChatbackground());
                if (UpdateUserGroupNameNotify.UPDATE_CHAT_BACKGROUND == content.getUpdatetype()) {
                    updateChatBackGround(messageService, userGroup);
                }
                if (UpdateUserGroupNameNotify.UPDATE_NICKNAME == content.getUpdatetype()) {
                    updateUserGroupName(messageService, record.getOperatorUserId(), userGroup);
                }
                sendMessage(messageService, record);// 发送消息
                feature.complete(record);
            } catch (Exception e) {
                feature.completeExceptionally(e);
            }

            return feature;
        }

        @Override
        protected Class getContentClass() {
            return UpdateUserGroupNameNotify.class;
        }

    }

    @Comment("全员禁言")
    public static final class ForBiddenWordHandler extends GroupHandler {

        public static final MessageHandler instance = new ForBiddenWordHandler();

        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            DataSource source = messageService.getSource();
            ForBiddenWordNotify forBiddenWord = (ForBiddenWordNotify) record.getContentObj();
            // 群组禁言处理
            updateSystemSetting(messageService, record, record.getTargetid(), UserGroup.SYSSETTING_FORBIDDEN_WORDS_INDEX, (forBiddenWord.getStatus() == 10 ? 0 : 1));
            BasicContent.TipMessage tipMessage = new BasicContent.TipMessage();
            tipMessage.setType(BasicContent.TipMessage.GROUP_FORBIT_WORD_TP);//群禁言
            tipMessage.setContent(forBiddenWord.getStatus() == 10 ? 
            			 retInfo(record.getLocal(), GROUP_ENABLEWORD)
            			: retInfo(record.getLocal(), GROUP_FORBIDDENWORD));
            tipMessage.setExtra(forBiddenWord);
            {
                long now = System.currentTimeMillis();
                MessageRecord tipRecord = new MessageRecord();
                tipRecord.setMsgtype(BasicContent.TipMessage.TYPE);
                tipRecord.setFromid(record.getFromid());
                tipRecord.setContent(jsonConvert.convertTo(tipMessage));
                tipRecord.setMsgkind(MessageRecord.MSG_KIND_GROUP);// 群发
                tipRecord.setMessageid(record.getTargetid() + "-" + record.getFromid() + "-" + Utility.format36time(now));
                tipRecord.setCreatetime(now);
                tipRecord.setTargetid(record.getTargetid());
                 messageService.insertQueue.add(tipRecord); // 保存数据库
                // 群发给 被拉进群的用户
                sendMessage(messageService, tipRecord);
            }
            feature.complete(record);
            return feature;
        }

        @Override
        protected Class getContentClass() {
            return ForBiddenWordNotify.class;
        }
    }

    @Comment("对好友进行隐身")
    public static final class StealthWithFriendsHandler extends NotifyHandler {

        public static final MessageHandler instance = new StealthWithFriendsHandler();

        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            StealthWithFriendsNotify content = (StealthWithFriendsNotify) record.getContentObj();
            int fromid = record.getFromid();
            // 更新所有好友对其的状态
            DataSource source = messageService.getSource();
            List<Integer> friendList = null;
            if ((friendList = content.getFriendids()) != null && friendList.size() > 0) {
                friendList.forEach(friendId -> {
                    // 对好友进行隐身
                    updateRelstatus(messageService, fromid, friendId, content.getRelstatus());// 对好友进行隐身

                });
                //
                sendNotifyMessageWithSave(messageService, record, friendList);
            }

            feature.complete(record);
            return feature;
        }

        public RetResult updateRelstatus(MessageService messageService, int userid, int friendid, int relstatus) {
            DataSource source = messageService.getSource();
            if (!(friendid > 0) || !(relstatus > 0)) {
                return RetCodes.retResult(RetCodes.RET_PARAMS_ILLEGAL);
            }
            int rows = source.updateColumn(FriendShip.class, FilterNode.create("userid", FilterExpress.EQUAL, friendid)
                    .and("friendid", FilterExpress.EQUAL, userid), ColumnValue.mov("relstatus", relstatus));
            if (rows > 0) {
                return RetResult.success(rows);
            }
            return RetCodes.retResult(RetCodes.RET_FRIENDSHI_FRIENDINFO_NOTEXIT_FIRIND);
        }

        @Override
        protected Class getContentClass() {
            return StealthWithFriendsNotify.class;
        }
    }

    @Comment("用户在线状态")
    public static class UserOnlineStatusHandler extends NotifyHandler {

        public static final MessageHandler instance = new UserOnlineStatusHandler();

        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            sendMessage(messageService, record);// 发送消息
            feature.complete(record);
            return feature;
        }

        @Override
        protected Class getContentClass() {
            return UserOnlineStatusNotify.class;
        }
    }

    @Comment("好友或者群在线状态")
    public static class OnlineUserListHandler extends NotifyHandler {

        public static final MessageHandler instance = new OnlineUserListHandler();

        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            sendMessage(messageService, record);// 发送消息
            feature.complete(record);
            return feature;
        }

        @Override
        protected Class getContentClass() {
            return NotifyContent.OnlineUserListNotify.class;
        }
    }

    @Comment("删除好友")
    public static final class ContactRemoveFriendHandler extends NotifyHandler {

        public static final MessageHandler instance = new ContactRemoveFriendHandler();

        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            NotifyContent.ContactRemoveFriendNotify content = (NotifyContent.ContactRemoveFriendNotify) record.getContentObj();
            int fromid = record.getFromid();
            // 更新所有好友对其的状态
            DataSource source = messageService.getSource();
            // 对好友进行隐身
            messageService.updateQueue.add(() -> {
                source.updateColumn(FriendShip.class, FilterNode.create("friendid", FilterExpress.EQUAL, fromid),
                        "relstatus");
            });
            messageService.deleteQueue.add(() -> {
                source.delete(FriendShip.class,
                        FilterNode.create("friendid", FilterExpress.EQUAL, fromid)
                                .and("userid", FilterExpress.EQUAL, content.getTargetUserId())
                                .or(FilterNode.create("friendid", FilterExpress.EQUAL, content.getTargetUserId())
                                        .and("userid", FilterExpress.EQUAL, fromid)));
            });
            sendMessage(messageService, record);// 发送消息
            feature.complete(record);
            return feature;
        }

        @Override
        protected Class getContentClass() {
            return NotifyContent.ContactRemoveFriendNotify.class;
        }

    }

    @Comment("消息撤回")
    public static final class ReCallNotifyHandler extends NotifyHandler {

        public static final MessageHandler instance = new ReCallNotifyHandler();

        @Override
        protected RetResult validate(MessageService messageService, MessageRecord record) {
            return super.validate(messageService, record); //To change body of generated methods, choose Tools | Templates.
        }
        
        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            logger.finest("record ================================================" + record);
            sendMessage(messageService, record);// 发送消息
            logger.finest("record ================================================" + record);
            return feature.completedFuture(record);
        }

        @Override
        protected Class getContentClass() {
            return NotifyContent.ReCallNotify.class;
        }
    }

    @Comment("撤回全部")
    public static final class ReCallAllNotifyHandler extends NotifyHandler {

        public static final MessageHandler instance = new ReCallNotifyHandler();

        @Override
        protected RetResult validate(MessageService messageService, MessageRecord record) {
            return super.validate(messageService, record); //To change body of generated methods, choose Tools | Templates.
        }
        
        @Override
        public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
            CompletableFuture<MessageRecord> feature = new CompletableFuture();
            logger.finest("wwwwwwwwwwwwwwwwwwwwwwwwwwwwww record ===" + record);
            sendMessage(messageService, record);// 发送消息
            feature.complete(record);
            return feature;
        }

        @Override
        protected Class getContentClass() {
            return NotifyContent.ReCallAllNotify.class;
        }
    }
    
    
    @Comment("退出H5登录")
    public static final class LogOutH5Handler extends NotifyHandler {
    	
    	public static final MessageHandler instance = new LogOutH5Handler();
    	@Override
    	public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
    		CompletableFuture<MessageRecord> feature = new CompletableFuture();
    		return feature.completedFuture(record);
    	}
    	
		@Override
		protected Class getContentClass() {
			// TODO Auto-generated method stub
			return NotifyContent.LogOutH5Notify.class;
		}
    	
    }
    
    @Comment("退出App 登录状态显示 未登录")
    public static final class DisableH5StatusHandler extends NotifyHandler {
    	
    	public static final MessageHandler instance = new DisableH5StatusHandler();
    	@Override
    	public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
    		CompletableFuture<MessageRecord> feature = new CompletableFuture();
    		return feature.completedFuture(record);
    	}
    	
		@Override
		protected Class getContentClass() {
			// TODO Auto-generated method stub
			return NotifyContent.DisableH5Status.class;
		}
    	
    }
    
    @Comment("输入阅读状态")
    public static final class InputReadStateHandler extends NotifyHandler {
    	
    	public static final MessageHandler instance = new InputReadStateHandler();
    	@Override
    	public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
    		CompletableFuture<MessageRecord> feature = new CompletableFuture();
    		sendMessage(messageService, record);// 发送消息
    		return feature.completedFuture(record);
    	}
    	
		@Override
		protected Class getContentClass() {
			// TODO Auto-generated method stub
			return NotifyContent.InputReadStateNotify.class;
		}
    }
    
    @Comment("群消息回执")
    public static final class GroupReadReceiptNotifyHandler extends NotifyHandler {
    	
    	public static final MessageHandler instance = new GroupReadReceiptNotifyHandler();
    	@Override
    	protected RetResult validate(MessageService messageService, MessageRecord record) {
    		// TODO Auto-generated method stub
    		GroupReadReceiptNotify notify = (GroupReadReceiptNotify) record.getContentObj();
    		return super.validate(messageService, record);
    	}
    	@Override
    	public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
    		CompletableFuture<MessageRecord> feature = new CompletableFuture();
    		sendMessage(messageService, record);// 发送消息
    		return feature.completedFuture(record);
    	}
    	
		@Override
		protected Class getContentClass() {
			// TODO Auto-generated method stub
			return NotifyContent.GroupReadReceiptNotify.class;
		}
    }
    
    //
    
    @Comment("群类型转化")
    public static final class GroupUpdateTypeNotifyHandler extends NotifyHandler {
    	
    	public static final MessageHandler instance = new GroupUpdateTypeNotifyHandler();
    	@Override
    	public CompletableFuture<MessageRecord> handler(MessageService messageService, MessageRecord record) {
    		CompletableFuture<MessageRecord> feature = new CompletableFuture();
    		NotifyContent.GroupUpdateTypeNotify content = (NotifyContent.GroupUpdateTypeNotify)record.getContentObj();
    		// 更新群类型
    		messageService.updateQueue.add(() -> {
    			messageService.getSource().updateColumnAsync(GroupDetail.class, FilterNode.create("groupid", FilterExpress.EQUAL, record.getTargetid()),
    						ColumnValue.mov("grouptype", content.getGrouptype())).whenComplete((r, e) -> {
    							 BasicContent.TipMessage tipMessage = new BasicContent.TipMessage();
    					            tipMessage.setType(BasicContent.TipMessage.GROUP_UPDATE_GROUPTYPE_TP);//创建群
    					            /**
    					             * 切换匿名群成功 切换普通群成功
    					             */
    					            tipMessage.setContent(content.isAnnoymousGroup() ? retInfo(record.getLocal(), GROUP_UPDATEANNOYTYPE) : retInfo(record.getLocal(), GROUP_UPDATENORMALTYPE));
    					            tipMessage.setExtra(content);
    					            {
    					            	try {
    					            		updateGroupIndex(messageService,  content.getGrouptype(),  record.getTargetid());
										} catch (Exception e2) {
											e2.printStackTrace();
											logger.finest("updateGroupIndex  error =======>>>>>>" +  e2.getMessage());
										}
    					                long now = System.currentTimeMillis();
    					                MessageRecord tipRecord = new MessageRecord();
    					                tipRecord.setMsgtype(BasicContent.TipMessage.TYPE);
    					                tipRecord.setFromid(record.getFromid());
    					                tipRecord.setContent(jsonConvert.convertTo(tipMessage));
    					                tipRecord.setMsgkind(MessageRecord.MSG_KIND_GROUP);// 群发
    					                tipRecord.setMessageid(record.getFromid() + "-" +  record.getTargetid() + "-" + Utility.format36time(now));
    					                tipRecord.setCreatetime(now);
    					                tipRecord.setTargetid(record.getTargetid());
    					                // 群发给 被拉进群的用户
    					                sendMessage(messageService, tipRecord);
    					                // tip  消息保存
    					                messageService.insertQueue.add(tipRecord);
    					            }
    					    		sendMessage(messageService, record);// 发送消息
    						});});
    		
    		return feature.completedFuture(record);
    	}
    	/**
    	 * 此段代码 后期 需要删除 目前为了 兼容之前的雷数据 需要更新群用户索引
    	 * @param messageService
    	 * @param grouptype
    	 * @param groupid
    	 */
    	@Comment("更新群索引")
    	private void updateGroupIndex(MessageService messageService, int grouptype, int groupid) {
    		List<UserGroup> rows = messageService.getSource()
    					.queryList(UserGroup.class,
    								Flipper.sortIfAbsent(new Flipper(65535), "jointime asc") ,
    								FilterNode.create("groupid", FilterExpress.EQUAL, groupid));
    		if (rows.isEmpty()) return;
    		if (grouptype == GroupDetail.GROUP_TYPE_ANONYMOUS ) {
    			for (int i = 0; i < rows.size(); i++) {
					UserGroup obj = rows.get(i);
					if (obj.getAnnoyindex() > 0) return; //已经更新的不用在更新  
					obj.setAnnoyindex(i+1);
				}
    			messageService.getSource().update(rows);
    		} else {
    			//    			messageService.getSource().updateColumn(UserGroup.class, FilterNode.create("groupid", FilterExpress.EQUAL, groupid), ColumnValue.mov("annoyindex", 0));
    		}
    	}
    	
		@Override
		protected Class getContentClass() {
			// TODO Auto-generated method stub
			return NotifyContent.GroupUpdateTypeNotify.class;
		}
    }
}
